﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;


namespace FloatBall
{
    static class Effects
    {
        const int MAX_SMOKE = 40;
        const int MAX_BUBBLES = 30;
        const int MAX_PARTICLES = 500;

        //Particle system vars
        private static int currentParticle = 0;
        private static int particleIndex;
        private static int stopAt;
        private static BasicEffect effect;



        public struct FastRand
        {
            const int NUM_RANDS = 1000;
            
            private static int t;
            private static int[] randInts = new int[NUM_RANDS];
            private static float[] randFloats = new float[NUM_RANDS];


            public static void Init()
            {
                Random rand = new Random();
                
                t = 0;

                for (int n = 0; n < NUM_RANDS; n++)
                {
                    randInts[n] = rand.Next(50);
                    randFloats[n] = 2f * (float)rand.NextDouble() - 1f;
                }

            }

            public static int GetInt()
            {
                t++;
                return randInts[t % NUM_RANDS];
            }

            public static float GetFloat()
            {
                t++;
                return randFloats[t % NUM_RANDS];
            }


        }


        public struct Particle
        {
            const int MIN_LIFE_TIME = 1;
            const float AIR_RESISTANCE = 0.96f;
            public const float SCALE = 0.6f;

            public Vector3 pos;
            public static Texture2D sprite;
            public bool isActive;
            
            int lifeLeft;
            Vector3 vel;

            public void Init()
            {
                isActive = false;
                lifeLeft = 0;
                pos = Vector3.Zero;
                vel = Vector3.Zero;
            }

            public void Create(ref Vector3 newPos, ref Vector3 newVel, ref Vector3 randomSpread)
            {
                isActive = true;
                lifeLeft = MIN_LIFE_TIME + FastRand.GetInt();
                pos = newPos;
                vel = newVel + new Vector3(FastRand.GetFloat() * randomSpread.X, FastRand.GetFloat() * randomSpread.Y, FastRand.GetFloat() * randomSpread.Z);
            }

            public void Update()
            {
                if (lifeLeft <= 0)
                    isActive = false;
                else
                {
                    lifeLeft--;
                    vel.Y += Constants.GRAVITY;
                    vel *= AIR_RESISTANCE;
                    pos += vel;
                }


            }

        }

        public static Particle[] particle = new Particle[MAX_PARTICLES];





        public static void Init()
        {
            FastRand.Init();

            for (int n = 0; n < MAX_PARTICLES; n++)
                particle[n].Init();


            effect = new BasicEffect(Game1.graphicsDevice);

            
        }





        public static void CreateParticle(Vector3 pos, Vector3 vel, Vector3 spread)
        {
            stopAt = currentParticle + MAX_PARTICLES;

            for (particleIndex = currentParticle; particleIndex < stopAt; particleIndex++)
            {
                currentParticle = particleIndex % MAX_PARTICLES;

                if (particle[currentParticle].isActive == false)
                {
                    particle[currentParticle].Create(ref pos, ref vel, ref spread);
                    currentParticle++;
                    break;
                }
            }


        }


        public static void Update()
        {
            for (int n = 0; n < MAX_PARTICLES; n++)
                if (particle[n].isActive)
                    particle[n].Update();


        }



        public static void DrawEffects(ref Matrix viewMatrix)
        {
            Vector3 transformedPosition;
            
            Matrix invertY = Matrix.CreateScale(1f, -1f, 1f);

            effect.World = invertY;
            effect.View = Matrix.Identity;
            effect.Projection = Render.projectionMatrix;
            effect.TextureEnabled = true;

            
            Vector2 origin = new Vector2(4f);
            Matrix invViewTransform = viewMatrix * invertY;
            
            Game1.spriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, effect);

            for (int n = 0; n < MAX_PARTICLES; n++ )
            {
                if (particle[n].isActive)
                {
                    transformedPosition = Vector3.Transform(particle[n].pos, invViewTransform);
                    Game1.spriteBatch.Draw(Particle.sprite, new Vector2(transformedPosition.X, transformedPosition.Y), null, Color.White, 0, origin, Particle.SCALE, SpriteEffects.None, transformedPosition.Z);
                }
            }

            Game1.spriteBatch.End(); 



        }



    }
}
